; (function (window,undefined) {
    // 工具对象
    var Tools = {
        // 生成指定范围的随机整数
        getRandom: function (min, max) {
            return Math.floor(Math.random() * (max - min + 1)) + min;
        },
        // 对象拷贝
        extend: function (parent, child) {
            for (var key in parent) {
                if (child[key]) {
                    continue;
                }
                child[key] = parent[key];
            }
        }
    }
    //将工具对象Tools暴露给外部作用域
    window.Tools=Tools;
})(window,undefined);

/*+++++++++++++++++++++++++++食物对象food.js+++++++++++++++++++++++++++*/
;// 自调用函数避免变量命名冲突
(function (window,undefined) {

    var position = 'absolute';
    // 用于存放食物dom对象的数组
    var elements = [];
    /*
        parent:地图对象
        options:食物对象的属性
    */
    function Food(map, options) {
        options = options || {}
        this.width = options.width || 20;
        this.height = options.height || 20;
        this.backgroundColor = this.backgroundColor || 'green';
        this.position = position;
        this.x = options.x || 0;
        this.y = options.y || 0;
    }

    // 初始化食物
    Food.prototype.render = function (map) {
        // 先删除之前的食物
        remove();
        //创建div
        div = document.createElement('div');
        // 将食物div挂载到页面上
        map.appendChild(div);

        // 将食物的dom对象存入数组
        elements.push(div);

        // 随机生成x坐标
        this.x = Tools.getRandom(0, map.offsetWidth / this.width - 1) * this.width;
        // 随机生成y坐标
        this.y = Tools.getRandom(0, map.offsetHeight / this.height - 1) * this.height;
        //设置样式
        div.style.left = this.x + 'px';
        div.style.top = this.y + 'px';
        div.style.width = this.width + 'px';
        div.style.height = this.height + 'px';
        div.style.backgroundColor = this.backgroundColor;
        div.style.position = this.position;

    }

    // 移除食物:因为此方法只在食物对象中使用,故声明称函数,可以保护其不会被外部作用域访问到
    function remove() {
        // 1-删除数组;删除数组的时候一定要从后往前删,否则数组元素删除不完
        for (var i = elements.length - 1; i >= 0; i--) {
            // 注意:顺序不能颠倒
            // 1-删除页面上的食物:先找到父元素,然后父元素调用removeChild()删除子元素
            elements[i].parentNode.removeChild(elements[i]);
            // 2-从数组中删除
            elements.splice(i, 1);
        }

    }

    // 将食物构造函数通过全局window对象暴露给外部作用域
    window.Food=Food;
})(window,undefined);


/*+++++++++++++++++++++++++++蛇对象snake.js+++++++++++++++++++++++++++*/
(function () {
    var position = 'absolute';
    // 用于保存蛇节dom对象的数组
    var elements = [];
    // 蛇构造函数
    function Snake(options) {
        // 防止用户不传递参数导致代码报错
        options = options || {};
        this.width = options.width || 20;
        this.height = options.height || 20;
        this.position = position;
        // 记录蛇移动的方向
        this.direction = options.direction || 'right';
        // 蛇身配置项,蛇初始状态由3个蛇节组成
        this.body = [
            {
                x: 2,
                y: 0,
                color: 'red'
            },
            {
                x: 1,
                y: 0,
                color: 'blue'
            },
            {
                x: 0,
                y: 0,
                color: 'blue'
            }
        ]
    }

    // map:地图dom对象
    Snake.prototype.render = function (map) {
        for (var i = 0; i < this.body.length; i++) {
            var div = document.createElement('div');
            map.appendChild(div);
            // 将蛇节对象压入数组
            elements.push(div);
            div.style.position = this.position;
            div.style.width = this.width + 'px';
            div.style.height = this.height + 'px';
            div.style.backgroundColor = this.body[i].color;
            div.style.left = this.body[i].x * this.width + 'px';
            div.style.top = this.body[i].y * this.height + 'px';
        }
    }

    /*
        移动:删除原来的蛇,按照新坐标重新绘制一条蛇
        注意:此方法中只是修改蛇节的坐标信息,重新渲染交给render方法来完成
    */
    Snake.prototype.move = function (food, map) {
        // 1-删除原来的蛇
        remove();
        // 2-移动蛇节:把前一节的坐标赋值给后一节即可;蛇头需要特殊处理,和移动方向相关
        for (var i = this.body.length - 1; i > 0; i--) {
            this.body[i].x = this.body[i - 1].x;
            this.body[i].y = this.body[i - 1].y;
        }
        var head = this.body[0];
        switch (this.direction) {
            // left
            case 'left':
                head.x -= 1;
                break;
            // top
            case 'top':
                head.y -= 1;
                break;
            // right
            case 'right':
                head.x += 1;
                break;
            // bottom
            case 'bottom':
                head.y += 1;
                break;
        }

        /*
            3-判断蛇头是否吃到食物
            注意:此处蛇节的x,y存储的不是具体的像素单位,要转换成具体的像素单位,在和食物的坐标进行比较
        */
        var headX = head.x * this.width;
        var headY = head.y * this.height;
        if (headX == food.x && headY == food.y) {
            // console.log('吃到食物了');
            // 1-重新生成食物
            food.render(map);
            // 2-增加蛇身
            var last = this.body[this.body.length - 1];
            // this.body[this.body.length]={
            //     x:last.x,
            //     y:last.y,
            //     color:last.color
            // }
            //使用对象的拷贝优化代码
            var obj = {};
            Tools.extend(last, obj);
            this.body[this.body.length] = obj;
        }

        // 3-重新渲染蛇身
        // this.render(map);
    }

    //删除蛇
    function remove() {
        for (var i = elements.length - 1; i >= 0; i--) {
            // 删除div
            elements[i].parentNode.removeChild(elements[i]);
            // 删除数组中的元素
            elements.splice(i, 1);
        }
    }   
    //将Snake暴露给外部作用域
    window.Snake = Snake;
})(window,undefined);

/*+++++++++++++++++++++++++++游戏对象game.js+++++++++++++++++++++++++++*/
(function (window,undefined) {
    // 记录游戏对象
    var that;
    /*
        map:地图对象
    */
    function Game(map) {
        //蛇对象
        this.snake = new Snake();
        //食物对象
        this.food = new Food();
        //地图对象
        this.map = map;
        //把游戏对象保存在全局变量that中
        that = this;
    }
    // 开始游戏
    Game.prototype.start = function () {
        this.snake.render(this.map);
        this.food.render(this.map);
        // 调用移动函数
        runSnake();
        // 注册键盘事件-控制移动方向
        bindKey();
       
    }
    //注册鼠标事件
    function bindKey() {
        document.addEventListener('keydown', function (event) {
            // 事件对象兼容处理
            event = window.event || event;
            switch (event.keyCode) {
                case 37:
                    that.snake.direction = 'left';
                    break;
                case 38:
                    that.snake.direction = 'top';
                    break;
                case 39:
                    that.snake.direction = 'right';
                    break;
                case 40:
                    that.snake.direction = 'bottom';
                    break;
            }
            
        }, false)
    }

    // 移动方法
    function runSnake() {
        var timerId = setInterval(function(){
            // 1-移动:仅仅修改蛇节坐标信息
            that.snake.move(that.food,that.map);
            // 2-重新在页面上绘制一条蛇
            that.snake.render(that.map);
            // 3-控制蛇头不能走出地图
            var maxX=that.map.offsetWidth/that.snake.width; 
            var maxY=that.map.offsetHeight/that.snake.height; 
            var headX=that.snake.body[0].x;
            var headY=that.snake.body[0].y;
            if(headX<0||headX>=maxX){
                alert('game over!!!');
                clearInterval(timerId);
            }
            if(headY<0||headY>=maxY){
                alert('game over!!!');
                clearInterval(timerId);
            }
        }, 150);
    }
    window.Game = Game;
})(window,undefined);
/*++++++++++++++++++++++++++++++++++++调用代码main.js++++++++++++++++++++++++++++++++++*/
;(function(window,undefined){
    var map = document.getElementById('container');
    var g1 = new Game(map);
    g1.start(window,undefined);
})()
